package com.SmartCare.service.impl.role;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.SmartCare.common.vo.role.*;
import com.SmartCare.mapper.homeInfo.CareHomeDetailsMapper;
import com.SmartCare.pojo.homeInfo.CareHomeDetails;
import com.SmartCare.pojo.role.ElderlyInformation;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.SmartCare.common.enums.Constants;
import com.SmartCare.common.Result;
import com.SmartCare.common.exception.ServiceException;
import com.SmartCare.common.enums.ElderlyCareRole;
import com.SmartCare.common.properties.WeChatProperties;
import com.SmartCare.common.dto.role.UserDTO;
import com.SmartCare.mapper.role.UserMapper;
import com.SmartCare.pojo.role.User;
import com.SmartCare.service.role.UserRelationshipService;
import com.SmartCare.service.role.UserService;
import com.SmartCare.utils.CommonTools;
import com.SmartCare.utils.HttpClientUtil;
import com.SmartCare.utils.TokenUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户表 服务实现类
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    //微信服务接口地址
    public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";
    //微信获取手机号的接口地址
    public static final String WX_PHONE = "https://api.weixin.qq.com/wxa/business/getuserphonenumber";
    //获取手机号需要的token的接口地址
    public static final String WX_TOKEN = "https://api.weixin.qq.com/cgi-bin/token";
    @Resource
    private UserMapper userMapper;
    @Resource
    private WeChatProperties weChatProperties;
    @Resource
    private UserRelationshipService userRelationshipService;
    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private CareHomeDetailsMapper careHomeDetailsMapper;

    public Result login(User user) {
        //检查传入数据是否合法

        //检查密码是否为非空
        if (StringUtils.isBlank(user.getPassword())) {
            throw new ServiceException(Constants.CODE_400, "密码不能为空");
        }
        //检查用户名和手机号是否同时为空
        if (StringUtils.isBlank(user.getName()) && StringUtils.isBlank(user.getPhone())) {
            throw new ServiceException(Constants.CODE_400, "用户名不能为空");
        }

        //建立查询所需的变量
        User one;
        QueryWrapper<User> qw = new QueryWrapper<>();
        //判断是通过用户名还是手机号登录
        if (StringUtils.isBlank(user.getName())) {
            //通过手机号登录
            qw.eq("phone", user.getPhone());
        } else if (StringUtils.isBlank(user.getPhone())) {
            //通过用户名进行登录
            qw.eq("name", user.getName());
        } else {
            //用户名和手机号同时不为空
            throw new ServiceException(Constants.CODE_400, "用户名和手机号不能同时传入");
        }
        //检查密码是否正确
        one = getOne(qw);
        if (one == null) {
            throw new ServiceException(Constants.CODE_400, "用户不存在");
        }
        if (!one.getStatus()) {
            throw new ServiceException(Constants.CODE_401, "该用户被禁用");
        }
        if (one.getRole() != 2) {
            return Result.error(Constants.CODE_401, "该用户权限不足");
        }
        if (!one.getPassword().equals(user.getPassword())) {
            throw new ServiceException(Constants.CODE_400, "密码错误");
        }

        //密码正确，将用户信息整合token后返回
        UserDTO userDTO = new UserDTO();
        //把查询到的用户信息copy到userDTO对象上
        BeanUtil.copyProperties(one, userDTO, true);
        //设置token
        String token = TokenUtils.genToken(one.getUserId().toString(), one.getPassword());
        userDTO.setToken(token);
        //将dto对象返回
        return Result.success(userDTO);
    }

    @Override
    public Result register(User user) {
        //检查邮箱是否已被绑定
        User one = getOne(new QueryWrapper<User>().eq("mail", user.getMail()));
        if (one != null) {
            throw new ServiceException(Constants.CODE_400, "该邮箱已绑定其他用户");
        }
        user.setStatus(true);
        user.setRole(-2);
        save(user);
        return Result.success();
    }

    @Override
    public Result listUsers(Integer pageNum, Integer pageSize, boolean mode) {
        //分页
        IPage<User> iPage = new Page<>(pageNum, pageSize);
        //根据mode确定查询的是管理员还是用户
        QueryWrapper<User> qw = new QueryWrapper<>();
        if (mode) {
            qw.ne("role", 1);
        } else {
            qw.eq("role", 1);
        }
        return Result.success(page(iPage, qw));
    }

    /**
     * 微信登录
     */
    public Result wxLogin(HttpServletRequest request, String openid) {
        if (request == null) {
            // 处理请求为null的情况，可以返回错误信息或采取其他措施
            return Result.error("非法请求");
        }
        //判断openid是否为空，如果为空表示登录失败，抛出业务异常
        if (openid == null) {
            throw new ServiceException(Constants.CODE_500, Constants.USER_NOT_LOGIN);
        }

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getOpenid, openid);
        //判断当前用户是否为新用户
        User user = userMapper.selectOne(queryWrapper);
        if (user != null) {
            // 获取或创建HttpSession对象
            HttpSession session = request.getSession(true);
            session.setAttribute("role", user.getRole());
            session.setAttribute("userId", user.getUserId());
            session.setAttribute("chName", user.getCareHomeName());
        }
        //如果是新用户，自动完成注册
        if (user == null) {
            user = User.builder()
                    .openid(openid)
                    .role(-2) //游客
                    .createdTime(LocalDateTime.now())
                    .status(true)
                    .city("")
                    .careHomeName("")
                    .build();
            userMapper.insert(user);
        }

        if (user.getStatus()) {
            //返回这个用户对象
            UserVo vo = UserVo.builder()
                    .id(user.getUserId())
                    .status(1)
                    .openid(user.getOpenid())
                    .identity(CommonTools.getRoleString(user.getRole()))
                    .careHomeName(user.getCareHomeName())
                    .build();
            return Result.success(vo);
        }
        return Result.error("账号不存在");
    }


    /**
     * 调用微信接口服务，获取微信用户的openid和session_key
     */
    @Override
    public OpenIdAndSessionKeyVO getOpenIdAndSessionKey(String code) {
        //调用微信接口服务，获得当前微信用户的openid
        Map<String, String> map = new HashMap<>();
        map.put("appid", weChatProperties.getAppid());
        map.put("secret", weChatProperties.getSecret());
        map.put("js_code", code);
        map.put("grant_type", "authorization_code");
        String json = HttpClientUtil.doGet(WX_LOGIN, map);

        JSONObject jsonObject = (JSONObject) JSONUtil.parse(json);
        String openid = jsonObject.getStr("openid");
        String session_key = jsonObject.getStr("session_key");

        return OpenIdAndSessionKeyVO.builder()
                .openid(openid)
                .session_key(session_key)
                .build();
    }

    /**
     * 获取用户手机号
     */
    @Override
    public Result getPhoneNumber(String code) {
        if (StringUtils.isEmpty(code)) {
            return Result.error("手机号获取凭证不能为空 !");
        }
        System.out.println("手机号获取凭证: " + code);

        try {
            //1. 通过appid和secret来获取token
            Map<String, String> map = new HashMap<>();
            map.put("appid", weChatProperties.getAppid());
            map.put("secret", weChatProperties.getSecret());
            map.put("grant_type", "client_credential");
            JSONObject jsonObject = (JSONObject) JSONUtil.parse(HttpClientUtil.doGet(WX_TOKEN, map));
            String accessToken = jsonObject.getStr("access_token");

            //2. 通过token和code来获取用户手机号

            //封装请求体
            Map<String, String> paramMap = new HashMap<>();
            paramMap.put("access_token", accessToken);
            paramMap.put("code", code);

            // 发送POST请求
            String response = HttpClientUtil.doPost(WX_PHONE, paramMap);
            // 转化返回结果为json对象
            JSONObject responseObject = (JSONObject) JSONUtil.parse(response);

            String errMsg = responseObject.getStr("errmsg");
            if (errMsg.equals("ok")) {
                JSONObject phoneInfoJson = responseObject.getJSONObject("phone_info");
                String phoneNumber = phoneInfoJson.getStr("purePhoneNumber");
                Map<String, String> vo = new HashMap<>();
                vo.put("phoneNumber", phoneNumber);
                return Result.success(vo);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.error("获取手机号失败: ");
    }

    @Override
    public Result getWorkerList(String careHomeName) {
        QueryWrapper<User> qw = new QueryWrapper<>();
        //只获取护工
        qw.eq("role", 1);
        //获取本养老院的护工
        qw.eq("care_home_name", careHomeName);
        return Result.success(list(qw));
    }

    @Override
    public Result updateNameAndIcon(Long userId, String avatarUrl, String nickName) {
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(User::getUserId, userId);
        if (avatarUrl != null && !avatarUrl.isEmpty()) {
            wrapper.set(User::getAvatarUrl, avatarUrl);
        }
        if (nickName != null && !nickName.isEmpty()) {
            wrapper.set(User::getNickname, nickName);
        }
        boolean res = update(wrapper);
        new LambdaQueryWrapper<ElderlyInformation>();
        return res ? Result.success("更新成功") : Result.error("更新失败");
    }

    @Override
    public Result getAllUser(String name) {
        //先获取养老院
        CareHomeDetails careHome = careHomeDetailsMapper.selectOne(new QueryWrapper<CareHomeDetails>().eq("name", name));
        if (careHome == null) {
            return Result.error(Constants.CODE_400, "养老院不存在");
        }
        return Result.success(list());
    }

    @Override
    public Result setUserData(Long id, String name, String phone) {
        User byId = getById(id);
        if (byId == null) {
            return Result.error("用户不存在");
        }
        if (name != null) {
            byId.setName(name);
        }
        if (phone != null) {
            byId.setPhone(phone);
        }
        updateById(byId);
        return Result.success();
    }

    @Override
    public List<Long> getIdsByCHName(String careHomeName) {

        // 获取该养老院的所有用户id
        QueryWrapper<User> uqw = new QueryWrapper<>();
        uqw.eq("care_home_name", careHomeName);
        uqw.select("user_id");
        List<User> users = userMapper.selectList(uqw);
        return users.stream().map(User::getUserId).collect(Collectors.toList());
    }


    @Override
    public Result search(Integer pageNum, Integer pageSize, String keyword, String type, boolean mode) {
        //分页
        IPage<User> iPage = new Page<>(pageNum, pageSize);
        //根据mode确定查询的是管理员还是用户
        QueryWrapper<User> qw = new QueryWrapper<>();
        if (mode) {
            qw.ne("role", 1);
        } else {
            qw.eq("role", 1);
        }
        //模糊查询
        qw.like(type, keyword);
        return Result.success(page(iPage, qw));
    }

    @Override
    public Result saveUser(User user) {
        //对参数做一些判断
        if (user.getPhone().length() > 11 || user.getIdentificationCard().length() > 18 || user.getCity().length() > 10 || user.getName().length() > 32) {
            throw new ServiceException(Constants.CODE_400, "参数长度不合法");
        }
        saveOrUpdate(user);
        return Result.success();
    }

    @Override
    public Result enable(Long id, Boolean enable) {
        User user = getById(id);
        if (user != null) {
            user.setStatus(enable);
            updateById(user);
        } else {
            throw new ServiceException(Constants.CODE_400, "不存在这样ID的用户");
        }
        return Result.success();
    }

    @Override
    public Result deleteUser(Long id) {
        removeById(id);
        return Result.success();
    }

    @Override
    public Result enableBatch(Boolean enable, List<Long> ids) {
        //先获取id数组中的用户集合
        List<User> users = listByIds(ids);
        //逐个修改属性
        for (User user : users) {
            user.setStatus(enable);
        }
        //更新数据
        updateBatchById(users);
        return Result.success();
    }

    /**
     * 批量删除用户
     *
     * @param idString 要进行删除的用户id数组字符串
     */
    @Override
    public Result deleteBatch(String idString) {
        //将字符串恢复为数组
        List<Long> ids = new ArrayList<>();
        String[] arr = idString.split(",");
        for (String s : arr) {
            ids.add(Long.parseLong(s));
        }
        removeBatchByIds(ids);
        return Result.success();
    }

    /**
     * 护工登录
     */
    @Override
    public Result workerLogin(HttpServletRequest request, String account, String password, String careHomeName) {

        //获取到用户，判断是否是护工
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.eq("name", account);
        User one = getOne(qw);
        if (one == null) {
            throw new ServiceException(Constants.LOGIN_FAILED, "用户不存在");
        } else if (one.getRole() != ElderlyCareRole.CAREGIVER.getValue()) {
            throw new ServiceException(Constants.LOGIN_FAILED, "该用户不是护工");
        } else if (!Objects.equals(password, one.getPassword())) {
            throw new ServiceException(Constants.LOGIN_FAILED, "密码错误");
        } else if (!one.getStatus()) {
            throw new ServiceException(Constants.LOGIN_FAILED, "用户已禁用");
        } else if (!one.getCareHomeName().equals(careHomeName)) {
            throw new ServiceException(Constants.LOGIN_FAILED, "用户不存在");
        }

        HttpSession session = request.getSession();
        session.setAttribute("role", one.getRole());
        session.setAttribute("userId", one.getUserId());
        session.setAttribute("chName", one.getCareHomeName());

        UserVo data = new UserVo();
        Integer status1 = one.getStatus() ? 1 : 0;
        data.setStatus(status1);
        data.setId(one.getUserId());
        return Result.success("登录成功", data);
    }

    /**
     * 家属个人信息查询
     */
    @Override
    public Result getFamilyInfo(Long userId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUserId, userId);
        wrapper.eq(User::getRole, 1);
        wrapper.eq(User::getStatus, 1);
        User one = getOne(wrapper);
        if (one == null) {
            return Result.error("用户不存在");
        }
        FamilyInfoVo vo = new FamilyInfoVo();
        BeanUtils.copyProperties(one, vo, "elders");

        List<ElderRelaVo> relationships = userRelationshipService.getElderIds(userId);
        vo.setElders(relationships);

        return Result.success(vo);
    }


    /**
     * 邮箱登录
     */
    @Override
    public Result loginByEmail(String name, String authCode) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getName, name);
        User user = getOne(wrapper);
        String email = user.getMail();

        // 获取当前连接的会话对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpSession session = null;
        if (attributes != null) {
            session = attributes.getRequest().getSession();
        }

        if (session != null) {
            session.setAttribute("role", user.getRole());
            session.setAttribute("userId", user.getUserId());
            session.setAttribute("chName", user.getCareHomeName());
        }

        //从redis中获取缓存验证码
        String codeInRedis = (String) redisTemplate.opsForValue().get(email);
        // 检查验证码是否存在并且未过期
        // 验证码不存在或已过期
        if (codeInRedis == null) {
            return Result.error("验证码不存在或者过期");
        }
        // 验证码未过期，继续验证登录逻辑
        if (codeInRedis.equals(authCode)) {
            //删除redis中的验证码
            redisTemplate.delete(email);
            UserVo data = new UserVo();
            Integer status1 = user.getStatus() ? 1 : 0;
            data.setStatus(status1);
            data.setId(user.getUserId());

            return Result.success("登录成功", data);
        }
        return Result.error("验证码错误");
    }

    /**
     * 修改密码
     */
    @Override
    public Result updatePwd(String name, String newPassword, String authCode) {
        if (name.isEmpty() || newPassword.isEmpty() || authCode.isEmpty()) {
            return Result.error("填写信息不完整");
        }
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getName, name);
        User one = getOne(wrapper);
        String email = one.getMail();

        //从redis中获取缓存验证码
        String codeInRedis = (String) redisTemplate.opsForValue().get(email);
        // 验证码不存在或已过期
        if (codeInRedis == null) {
            return Result.error("验证码不存在或者过期");
        }
        // 验证码未过期，继续验证
        if (codeInRedis.equals(authCode)) {
            //删除redis中的验证码
            redisTemplate.delete(email);

            //更新密码
            LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(User::getUserId, one.getUserId());
            updateWrapper.set(User::getPassword, newPassword);
            update(updateWrapper);

            return Result.success("修改密码成功");
        }
        return Result.error("验证码错误");
    }

    /**
     * 用户账号密码登录
     */
    @Override
    public Result userLogin(HttpServletRequest request, String account, String password, String careHomeName) {
        //获取到用户，判断是否是护工
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.eq("name", account);
        User one = getOne(qw);
        if (one == null) {
            throw new ServiceException(Constants.CODE_400, "用户不存在");
        } else if (!Objects.equals(password, one.getPassword())) {
            throw new ServiceException(Constants.CODE_400, "密码错误");
        } else if (!one.getStatus()) {
            throw new ServiceException(Constants.CODE_400, "此用户已禁用");
        } else if (!one.getCareHomeName().equals(careHomeName)) {
            throw new ServiceException(Constants.CODE_400, "该养老院非用户不存在");
        }

        HttpSession session = request.getSession();
        session.setAttribute("userId", one.getUserId());
        session.setAttribute("chName", one.getCareHomeName());

        UserVo data = new UserVo();
        Integer status1 = one.getStatus() ? 1 : 0;
        data.setStatus(status1);
        data.setId(one.getUserId());
        return Result.success("登录成功", data);
    }

    @Override
    public Result changePassword(String mail, String password) {
        //根据邮箱获取用户
        User one = userMapper.selectOne(new QueryWrapper<User>().eq("mail", mail));
        if (one == null) {
            throw new ServiceException(Constants.CODE_400, "不存在绑定了此邮箱的用户");
        }
        //修改密码
        one.setPassword(password);
        updateById(one);

        return Result.success();
    }

    /**
     * 游客注册
     */
    @Override
    public Result register(String account, String password, String careHomeName, Integer identity) {
        if (identity > 3) {
            return Result.error("请正确选择身份");
        }
        User role = User.builder()
                .nickname(account)
                .password(password)
                .careHomeName(careHomeName)
                .role(identity)
                .status(false)
                .build();
        boolean res = save(role);
        if (!res) {
            return Result.error("注册失败");
        }

        User user = new User();
        user.setRole(identity);
        user.setCareHomeName(careHomeName);

        return Result.success("注册成功", user);
    }
}
